// locutor
// (c) 2009-2010, Normen Müller, normen.mueller@gmail.com  
// $Id: RWS.scala 94 2010-06-12 15:35:36Z normen.mueller $
package locutor.rws

import java.io.File

import scaup.Views._

import locutor.rws.gm._
import locutor.rws.rs._

/** Companion to <code>RewriteSystem</code> class.
 * 
 *  @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 *  @version 0.0.5
 */
object RewriteSystem {
  val empty = new RewriteSystem(GraphModel.empty)

  def parse(system: String): RewriteSystem = parse(system.toFile)

  def parse(system: File): RewriteSystem =    
    if(system == null)
      error("Rewrite system may not be null.")
    else system.ext match {
      case Some("gm") => new RewriteSystem(GraphModel.parse(system))
      case Some("rs") => new RewriteSystem(RuleSystem.parse(system))
      case _          => error("Unknown rewrite system format.")
    }
}

/** A rewrite system.
 * 
 *  @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 *  @version 0.0.5
 */
class RewriteSystem private [locutor] (val system: Either[GraphModel, RuleSystem]) {
  private [locutor] def this(graphModel: GraphModel) = this(Left(graphModel))
  
  private [locutor] def this(ruleSystem: RuleSystem) = this(Right(ruleSystem))
  
  lazy val (graphModel, ruleSystem) = system match {
    case Left(graphModel)  => (graphModel, RuleSystem.empty)
    case Right(ruleSystem) => (ruleSystem.graphModel, ruleSystem) 
  }

  /** Join rewrite systems
   * 
   *  Joining rewrite systems maintains both the graph model name as well as the rule system name of the left-hand sided join operand.  That is, joining a rewrite system S
   *  to a rewrite system R (R join S) maintains the name of graph model GM(R) and the name of the rule system RS(R).
   * 
   *  @devnote: In case of ``this.system == Right(thatRuleSystem)'' utilizing ``new RewriteSystem(thatRuleSystem join thisGraphModel)'' corrupts name maintenance as
   *    described above.
   */
  def join(that: RewriteSystem) = system match {
    case Left(thisGraphModel)  => that.system match {
      case Left(thatGraphModel)  => new RewriteSystem(thisGraphModel join thatGraphModel)
      case Right(thatRuleSystem) => new RewriteSystem(new RuleSystem(thisGraphModel join thatRuleSystem.graphModel, thatRuleSystem.rules))
    } 
    case Right(thisRuleSystem) => that.system match {
      case Left(thatGraphModel)  => new RewriteSystem(new RuleSystem(thisRuleSystem.graphModel join thatGraphModel, thisRuleSystem.rules))
      case Right(thatRuleSystem) => new RewriteSystem(thisRuleSystem join thatRuleSystem)
    }
  }
  
  def withAnnotations = new RewriteSystem(ruleSystem withAnnotations)
  
  def withRippling = new RewriteSystem(ruleSystem withRippling)
}
